﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Lyx.Tools
{
    class BoundingRect
    {
        public Rectangle rectCollide;
        public float fRotation;
        public Vector2 vOrigin;

        public BoundingRect(Rectangle _rect, float _fInitialRotation)
        {
            rectCollide = _rect;
            fRotation = _fInitialRotation;
            vOrigin = new Vector2((_rect.Width / 2), (_rect.Height / 2));
        }

        public void UpdatePosition(Vector2 _vPosition, float _fRotation)
        {
            fRotation = _fRotation;
            rectCollide.X = (int)(_vPosition.X - vOrigin.X);
            rectCollide.Y = (int)(_vPosition.Y - vOrigin.Y);
        }

        public bool Intersects(BoundingRect _rect)
        {
            List<Vector2> listRectAxis = new List<Vector2>();
            listRectAxis.Add(UpperRightCorner() - UpperLeftCorner());
            listRectAxis.Add(UpperRightCorner() - LowerRightCorner());
            listRectAxis.Add(_rect.UpperLeftCorner() - _rect.LowerLeftCorner());
            listRectAxis.Add(_rect.UpperLeftCorner() - _rect.UpperRightCorner());

            foreach (Vector2 vAxis in listRectAxis)
            {
                if (!IsAxisCollision(_rect, vAxis))
                {
                    return false;
                }
            }

            return true;
        }

        private bool IsAxisCollision(BoundingRect _rect, Vector2 _vAxis)
        {
            List<int> listRectAScalars = new List<int>();
            listRectAScalars.Add(GenerateScalar(_rect.UpperLeftCorner(), _vAxis));
            listRectAScalars.Add(GenerateScalar(_rect.UpperRightCorner(), _vAxis));
            listRectAScalars.Add(GenerateScalar(_rect.LowerLeftCorner(), _vAxis));
            listRectAScalars.Add(GenerateScalar(_rect.LowerRightCorner(), _vAxis));

            List<int> listRectBScalars = new List<int>();
            listRectBScalars.Add(GenerateScalar(UpperLeftCorner(), _vAxis));
            listRectBScalars.Add(GenerateScalar(UpperRightCorner(), _vAxis));
            listRectBScalars.Add(GenerateScalar(LowerLeftCorner(), _vAxis));
            listRectBScalars.Add(GenerateScalar(LowerRightCorner(), _vAxis));

            int iRectAMinimum = listRectAScalars.Min();
            int iRectAMaximum = listRectAScalars.Max();
            int iRectBMinimum = listRectBScalars.Min();
            int iRectBMaximum = listRectBScalars.Max();

            if (iRectBMinimum <= iRectAMaximum && iRectBMaximum >= iRectAMaximum)
            {
                return true;
            }
            else if (iRectAMinimum <= iRectBMaximum && iRectAMaximum >= iRectBMaximum)
            {
                return true;
            }

            return false;
        }

        private int GenerateScalar(Vector2 _vRectCorner, Vector2 _vAxis)
        {
            float fNumerator = (_vRectCorner.X * _vAxis.X) + (_vRectCorner.Y * _vAxis.Y);
            float fDenominator = (_vAxis.X * _vAxis.X) + (_vAxis.Y * _vAxis.Y);
            float fDivisionResult = fNumerator / fDenominator;
            Vector2 vCornerProjected = new Vector2(fDivisionResult * _vAxis.X, fDivisionResult * _vAxis.Y);
            float fScalar = (_vAxis.X * vCornerProjected.X) + (_vAxis.Y * vCornerProjected.Y);

            return (int)fScalar;
        }

        private Vector2 RotatePoint(Vector2 _vPoint, Vector2 _vOrigin, float _fRotation)
        {
            Vector2 vTranslatedPoint = new Vector2();
            vTranslatedPoint.X = (float)(_vOrigin.X + (_vPoint.X - _vOrigin.X) * Math.Cos(_fRotation)
                - (_vPoint.Y - _vOrigin.Y) * Math.Sin(_fRotation));
            vTranslatedPoint.Y = (float)(_vOrigin.Y + (_vPoint.Y - _vOrigin.Y) * Math.Cos(_fRotation)
                + (_vPoint.X - _vOrigin.X) * Math.Sin(_fRotation));
            return vTranslatedPoint;
        }

        private Vector2 UpperLeftCorner()
        {
            Vector2 vUpperLeft = new Vector2(rectCollide.Left, rectCollide.Top);
            vUpperLeft = RotatePoint(vUpperLeft, vUpperLeft + vOrigin, fRotation);
            return vUpperLeft;
        }

        private Vector2 UpperRightCorner()
        {
            Vector2 vUpperRight = new Vector2(rectCollide.Right, rectCollide.Top);
            vUpperRight = RotatePoint(vUpperRight, vUpperRight + new Vector2(-vOrigin.X, vOrigin.Y), fRotation);
            return vUpperRight;
        }

        private Vector2 LowerLeftCorner()
        {
            Vector2 vLowerLeft = new Vector2(rectCollide.Left, rectCollide.Bottom);
            vLowerLeft = RotatePoint(vLowerLeft, vLowerLeft + new Vector2(vOrigin.X, -vOrigin.Y), fRotation);
            return vLowerLeft;
        }

        private Vector2 LowerRightCorner()
        {
            Vector2 vLowerRight = new Vector2(rectCollide.Right, rectCollide.Bottom);
            vLowerRight = RotatePoint(vLowerRight, vLowerRight + new Vector2(-vOrigin.X, -vOrigin.Y), fRotation);
            return vLowerRight;
        }

        public int X
        {
            set { rectCollide.X = value; }
            get { return rectCollide.X; }
        }

        public int Y
        {
            set { rectCollide.Y = value; }
            get { return rectCollide.Y; }
        }

        public int Width
        {
            set { rectCollide.Width = value; }
            get { return rectCollide.Width; }
        }

        public int Height
        {
            set { rectCollide.Height = value; }
            get { return rectCollide.Height; }
        }
    }
}
